package com.py.custom.tms.application.current;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * AbstractQueuedSynchronizer
 * 	1、继承该类，实现加锁和释放锁
 * 		a、独占锁
 * 			tryAcquire
 * 			tryRelease
 * 		b、共享锁
 * 			tryAcquireShared
 * 			tryReleaseShared
 * 	2、同步队列
 * 		acquire
 * 			a、tryAcquire
 * 			b、addWaiter
 * 				创建一个虚节点Node，然后把需要等待的线程封装成Node，连接这个两个节点。head是虚节点；tail是等待线程节点
 * 			c、acquireQueued
 * 				获取传入节点的上一个节点pre，判断pre是否是虚节点head，是再让该节点尝试获取锁，
 * 				成功就把该节点做为head节点，把对应的线程设置为null，上一个节点设置为null。
 * 				如果pre不是head，获取waitStatus的值，如果是-1就阻塞该线程。
 * 				不是则把当pre的waitStatus值设置为-1，然后在次循环，阻塞当前线程。等待锁释放。
 * 		release
 * 			a、tryRelease
 * 			b、unparkSuccessor
 * 				获取head节点，waitStatus值不为0；把waitStatus修改成0，然后获取next节点，
 * 				如果节点不为null 并且 waitStatus<= 0，把节点的线程唤醒。
 * 				如果 waitStatus>0，那么从tail节点的pre进行同样的逻辑唤醒
 * 	3、Condition
 * 		await
 * 			把当前线程加入到，Condition的firstWaiter、lastWaiter队列里面。
 * 			当前线程必须 是获取锁的状态，然后释放锁，并唤醒head的next节点。
 * 			判断当前线程的节点是CONDITION类型，阻塞该线程。
 * 		signal
 * 			获取firstWaiter，释放firstWaiter，修改节点类型，添加到同步队列尾部；获取到同步head.next节点
 * 			把firstWaiter的next 设置成firstWaiter；
 *
 * 		signalAll
 * 			获取firstWaiter，释放firstWaiter，修改节点类型，添加到同步队列尾部；获取到同步head.next节点
 * 			一直把所有的节点添加完。
 *
 * ReentrantLock
 */
public class JUCTest {

    public static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    public static ReentrantLock lock = new ReentrantLock();
    public static  Condition condition = lock.newCondition();

    public static void main(String[] args) {
        lockQueued();


        readWriteLock.readLock().lock();
        readWriteLock.readLock().unlock();

        readWriteLock.writeLock().lock();
        readWriteLock.writeLock().unlock();

    }


    public static void lockQueued() {
        new Thread(() -> {
            lock.lock();
            try {
                System.out.println("T1");
                try {
                    condition.await();
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } finally {
                lock.unlock();
            }
        }).start();

        new Thread(() -> {
            lock.lock();
            try {
                System.out.println("T2");
                condition.signal();
            } finally {
                lock.unlock();
            }
        }).start();

        new Thread(() -> {
            lock.lock();
            try {
                System.out.println("T2");

            } finally {
                lock.unlock();
            }
        }).start();

    }
}
